/*
 * System info
 */
package helper

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

func CpuUsage() string {
	cmd := exec.Command("ps", "aux")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return ""
	}

	var all float64
	for {
		line, err := out.ReadString('\n')
		if err != nil {
			break
		}
		tokens := strings.Split(line, " ")
		ft := make([]string, 0)
		for _, t := range tokens {
			if t != "" && t != "\t" {
				ft = append(ft, t)
			}
		}

		if ft[2] == "%CPU" {
			continue
		}
		cpu, err := strconv.ParseFloat(ft[2], 64)
		if err != nil {
			continue
		}
		all += cpu
	}
	return fmt.Sprintf("%.2f", all)
}

/*
 * disk usage of path/disk
 */
//func DiskUsage(path string) map[string]string {
//	mDisk := make(map[string]string)
//	sFs := syscall.Statfs_t{}
//	Err := syscall.Statfs(path, &sFs)
//	if Err != nil {
//		log.Println("ERROR", "170060|查询磁盘使用情况出错", Err.Error())
//		return mDisk
//	}
//	All := sFs.Blocks * uint64(sFs.Bsize) / 1024 / 1024
//	Free := sFs.Bfree * uint64(sFs.Bsize) / 1024 / 1024
//	mDisk["All"] = strconv.FormatUint(All, 10)
//	mDisk["Free"] = strconv.FormatUint(Free, 10)
//	mDisk["Used"] = strconv.FormatUint((All - Free), 10)
//	return mDisk
//}

//func MemStat() map[string]string {
//	//系统占用,仅linux/mac下有效
//	//system memory usage
//	mMem := make(map[string]string)
//	sysInfo := new(syscall.Sysinfo_t)
//	Err := syscall.Sysinfo(sysInfo)
//	if Err == nil {
//		All := sysInfo.Totalram / 1024 / 1024
//		Free := sysInfo.Freeram / 1024 / 1024
//		Swap := sysInfo.Totalswap / 1024 / 1024
//		SwapFree := sysInfo.Freeswap / 1024 / 1024
//		mMem["All"] = strconv.FormatUint(All, 10)   //* uint64(syscall.Getpagesize())
//		mMem["Free"] = strconv.FormatUint(Free, 10) //* uint64(syscall.Getpagesize())
//		mMem["Used"] = strconv.FormatUint(All-Free, 10)
//		mMem["Swap"] = strconv.FormatUint(Swap, 10)
//		mMem["SwapFree"] = strconv.FormatUint(SwapFree, 10)
//		mMem["SwapUsed"] = strconv.FormatUint(Swap-SwapFree, 10)
//		day := sysInfo.Uptime / 86400
//		hour := sysInfo.Uptime % 86400 / 3600
//		minute := sysInfo.Uptime % 86400 % 3600 / 60
//		tTime := time.Now().Unix() - sysInfo.Uptime
//		tNow := time.Unix(tTime, 10)
//		mMem["StartTime"] = tNow.Format("2006") + "-" + tNow.Format("01") + "-" + tNow.Format("02") + " " + tNow.Format("15") + ":" + tNow.Format("04") + ":" + tNow.Format("05")
//		mMem["Runtime"] = strconv.FormatInt(day, 10) + "天" + strconv.FormatInt(hour, 10) + "小时" + strconv.FormatInt(minute, 10) + "分钟"
//
//	} else {
//		log.Println("ERROR", "170060|查询内存使用情况出错", Err.Error())
//	}
//	return mMem
//}


/**
 * IO读写
 */
func IoUsage() map[string]string {
	cmd := exec.Command("iostat")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	mIo := make(map[string]string)
	if err != nil {
		log.Println("ERROR", "170061|系统命令iostat 执行错误", err.Error())
		return mIo
	}
	for {
		line, err := out.ReadString('\n')
		if err != nil {
			break
		}
		tokens := strings.Split(line, " ")
		ft := make([]string, 0)
		for _, t := range tokens {
			if t != "" && t != "\t" {
				fi := strings.Trim(t, "\n\t")
				ft = append(ft, fi)
			}
		}
		if ft[0] == "sda" {
			mIo["ReadSpd"] = ft[2]
			mIo["WriteSpd"] = ft[3]
			mIo["Read"] = ft[4]
			mIo["Write"] = ft[5]
		}
	}
	return mIo
}

/**
 *文件系统使用率
 */

func FileUsage() []interface{} {
	cmd := exec.Command("df", "-h")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	mList := make([]interface{}, 0)
	if err != nil {
		log.Println("ERROR", "170061|系统命令df -h执行错误", err.Error())
		return mList
	}
	var mRet map[string]string
	for {
		line, err := out.ReadString('\n')
		if err != nil {
			break
		}
		tokens := strings.Split(line, " ")
		ft := make([]string, 0)
		for _, t := range tokens {
			if t != "" && t != "\t" {
				fi := strings.Trim(t, "\n\t")
				ft = append(ft, fi)
			}
		}
		if ft[0] != "Filesystem" {
			mRet = make(map[string]string)
			mRet["FileSystem"] = ft[0]
			mRet["All"] = ft[1]
			mRet["Used"] = ft[2]
			mRet["Free"] = ft[3]
			mRet["UsePercent"] = ft[4]
			mRet["Mounted"] = ft[5]
			mList = append(mList, mRet)
		}
	}
	return mList
}

/**
 *系统负载1 5 10 分钟
 */
func LoadAverage() map[string]string {

	cmd := exec.Command("uptime")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	mRet := make(map[string]string)

	if err != nil {
		log.Println("ERROR", "170061|系统命令uptime执行错误", err.Error())
		return mRet
	}

	sLine, err := out.ReadString('\n')

	if err != nil {
		log.Println("ERROR", "170060|读取系统负载数据出错", err.Error())
		return mRet
	}
	//正则表达获取1 5 15 分钟系统负载数据
	sRegs := "\\d+\\.\\d+"

	sReg := regexp.MustCompile(sRegs)

	sLoadAverage := sReg.FindAllString(sLine, 3)

	if len(sLoadAverage) >= 3 {
		mRet["OneMin"] = sLoadAverage[0]

		mRet["FivMin"] = sLoadAverage[1]

		mRet["TenfivMin"] = sLoadAverage[2]
	} else {
		return mRet
	}
	return mRet
}

/**
 *网卡使用情况
 */
func NetUsage() []interface{} {

	var Net struct {
		NetCard  string
		Rbytes   string
		Rpackets string
		Rerrors  string
		Rpck     string
		Sbytes   string
		Spackets string
		Serrors  string
		Spck     string
	}
	cmd := exec.Command("ifconfig")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	aNetList := make([]interface{}, 0)
	if err != nil {
		log.Println("ERROR", "170060|查询网卡使用情况出错", err.Error())
		return aNetList
	}
	for {
		line, err := out.ReadString('\n')
		if err != nil {
			break
		}
		tokens := strings.Split(line, " ")
		ft := make([]string, 0)
		for _, t := range tokens {
			if t != "" && t != "\t" {
				fi := strings.Trim(t, "\n\t")
				ft = append(ft, fi)
			}
		}
		if ft[0] != "" {
			if ft[1] == "Link" {
				Net.NetCard = ft[0]
				sPck := NetBytes(ft[0])
				if len(sPck) >= 2 {
					Net.Rpck = sPck[0]
					Net.Spck = sPck[1]
				} else {
					Net.Rpck = "0.0"
					Net.Spck = "0.0"
				}
			}
			if ft[0] == "RX" {
				if strings.Contains(ft[1], "packets") {
					sPackets := strings.SplitAfter(ft[1], ":")
					Net.Rpackets = sPackets[1]
					sErrors := strings.SplitAfter(ft[2], ":")
					Net.Rerrors = sErrors[1]
				}
				if strings.Contains(ft[1], "bytes") {
					rBytes := strings.SplitAfter(ft[1], ":")
					Net.Rbytes = rBytes[1]
					sBytes := strings.SplitAfter(ft[5], ":")
					Net.Sbytes = sBytes[1]
					aNetList = append(aNetList, Net)
				}
			}
			if ft[0] == "TX" {
				if strings.Contains(ft[1], "packets") {
					sPackets := strings.SplitAfter(ft[1], ":")
					Net.Spackets = sPackets[1]
					sErrors := strings.SplitAfter(ft[2], ":")
					Net.Serrors = sErrors[1]
				}
			}

		}
	}
	return aNetList
}

/**
 *网卡实时流量
 */
func NetBytes(Iface string) []string {
	aBytesInfo := make([]string, 0)
	cmd := exec.Command("sar", "-n", "DEV", "1", "1")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Println("ERROR", "170060|查询实时流量情况出错", err.Error())
		return aBytesInfo
	}
	for {
		line, err := out.ReadString('\n')
		if err != nil {
			break
		}
		tokens := strings.Split(line, " ")
		ft := make([]string, 0)
		for _, t := range tokens {
			if t != "" && t != "\t" {
				fi := strings.Trim(t, "\n\t")
				ft = append(ft, fi)
			}
		}
		if ft[0] == "Average:" {
			if ft[1] == Iface {
				aBytesInfo = append(aBytesInfo, ft[2])
				aBytesInfo = append(aBytesInfo, ft[3])
			}
		}
	}
	return aBytesInfo
}

/**
 *网络配置
 */
func GetNetConfig() []interface{} {

	aNetCard := make([]interface{}, 0)
	cmd := exec.Command("cat", "/etc/network/interfaces")
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Println("ERROR", "170050|查询网卡配置信息出错", err.Error())
		return aNetCard
	}
	var mNetConfig map[string]string
	mNetConfig = make(map[string]string)

	for {

		line, err := out.ReadString('\n')
		if err != nil {
			break
		}
		nline := strings.Replace(line, "\t", " ", -1)
		tokens := strings.Split(nline, " ")
		ft := make([]string, 0)

		for _, t := range tokens {
			if t != "" {
				fi := strings.Trim(t, "\n")
				ft = append(ft, fi)
			}
		}

		switch ft[0] {
		case "auto":

			if len(ft) < 2 {
				ft = append(ft, " ")
			}
			if ft[1] != "lo" {
				mNetConfig["NetCard"] = ft[1]
			}

		case "netmask":

			if len(ft) < 2 {
				ft = append(ft, " ")
			}
			mNetConfig["NetMask"] = ft[1]

		case "gateway":

			if len(ft) < 2 {
				ft = append(ft, " ")
			}
			mNetConfig["GateWay"] = ft[1]

		case "address":

			if len(ft) < 2 {
				ft = append(ft, " ")
			}
			mNetConfig["Ip"] = ft[1]

		case "dns-nameservers":

			if len(ft) < 2 {
				ft = append(ft, "")
			}
			mNetConfig["Dns"] = ft[1]

		case "dns-nameserver":

			if len(ft) < 2 {
				ft = append(ft, "")
			}
			mNetConfig["Dns"] = ft[1]
		}

		if len(mNetConfig) == 5 {
			aNetCard = append(aNetCard, mNetConfig)
			mNetConfig = make(map[string]string)
		}

	}

	return aNetCard
}

/**
 *修改网络配置
 */
func PutNetConfig(mString map[string]string) error {

	bFile, err := ioutil.ReadFile("/etc/network/interfaces")

	if err != nil {
		log.Println("ERROR", "170050|读取网卡配置文件出错", err.Error())
		return err
	}

	var sName, sRegs string
	var Reg *regexp.Regexp
	mNetCard := make(map[string]string, 0)
	for i, v := range mString {
		var err error
		if v == "" {
			err = errors.New("参数值为空")
			return err
		}
		switch i {
		case "Ip":
			mNetCard["address"] = v
		case "GateWay":
			mNetCard["gateway"] = v
		case "Dns":
			mNetCard["dns-nameserver"] = v
		case "NetMask":
			mNetCard["netmask"] = v
		}
	}

	for i, v := range mNetCard {
		sName = i
		sRegs = sName + "\\s+\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"
		Reg = regexp.MustCompile(sRegs)
		bOld := Reg.Find(bFile)
		bFile = bytes.Replace(bFile, bOld, []byte(i+" "+v), 1)
	}

	err = ioutil.WriteFile("/etc/network/interfaces", bFile, 644)

	if err != nil {
		panic(err)
		log.Println("ERROR", "170051|写入网卡配置文件出错", err.Error())
		return err
	}

	return nil
}
